<?php

/**
 * @author sdnode & gpt
 * @license MIT
 * @since 2024-05-11
 */
namespace addons\csmitsm\library\sdnode\xstack\utils;

use InvalidArgumentException;

class XsArrayUtils
{
    /**
     * @group 基本操作
     * 数组长度
     * 
     * @param array $array 数组 如:['a', 'b', 'c']
     * @return int 返回比较结果 如:3
     */
    public static function length($array)
    {
        return count($array);
    }

    /**
     * @group 比较和检查
     * 比较两个数组是否相等。
     * 
     * @param array $a 第一个数组 如:['a', 'b', 'c']
     * @param array $b 第二个数组 如:['a', 'b', 'c']
     * @return bool 返回比较结果 如:true
     */
    public static function isEquals($a, $b)
    {
        return $a === $b;
    }

    /**
     * @group 比较和检查
     * 检查数组是否包含特定的元素。
     * 
     * @param array $array 需要检查的数组 如:['a', 'b', 'c']
     * @param mixed $element 需要检查的元素 如:'b'
     * @return bool 是否包含元素 如:true
     */
    public static function contains(array $array, $element)
    {
        return in_array($element, $array);
    }

    /**
     * @group 比较和检查
     * 检查数组是否为空。
     * 
     * @param array $array 需要检查的数组 如[]
     * @return bool 是否为空 如:true
     */
    public static function isEmpty(array $array)
    {
        return empty($array);
    }

    /**
     * @group 索引查找
     * 查找特定元素在数组中第一个索引。
     * 
     * @param array $array 需要查找的数组 如:['a', 'b', 'c']
     * @param mixed $element 需要查找的元素 如:b
     * @return int 元素的索引,找不到则返回-1
     */
    public static function indexOf(array $array, $element)
    {
        foreach($array as $index=>$item){
            if(static::isEquals($item, $element)){
                return $index;
            }
        }
        return -1;
    }

    /**
     * @group 索引查找
     * 查找特定元素在数组中出现的所有索引。
     * 
     * @param array $array 需要查找的数组 如:['a', 'b', 'c', 'b']
     * @param mixed $element 需要查找的元素 如:b
     * @return array 元素的所有索引数组，如返回[1, 3]
     */
    public static function indexesOf(array $array, $element)
    {
        $indexes = [];
        foreach($array as $index=>$item){
            if(static::isEquals($item, $element)){
                $indexes[] = $index;
            }
        }
        return $indexes;
    }

    /**
     * @group 索引查找
     * 根据对象的特定值到数组中查找第一个索引。
     * 
     * @param array $array 需要查找的数组 如:[["id"=>1],["id"=>2]]
     * @param string $searchKey 需要查找的对象的key 如:id
     * @param mixed $searchValue 需要查找的对象的值 如:2
     * @return array 元素的所有索引数组，如返回1
     */
    public static function indexOfByObjectKey(array $array,string $searchKey, $searchValue)
    {
        foreach($array as $index=>$item){
            if(isset($item[$searchKey]) && $item[$searchKey]==$searchValue){
                return $index;
            }
        }
        return -1;
    }  

    /**
     * @group 索引查找
     * 根据对象的特定值到数组中查找所有索引。
     * 
     * @param array $array 需要查找的数组 如:[["id"=>1],["id"=>2],["id"=>2]]
     * @param string $searchKey 需要查找的对象的key 如:id
     * @param mixed $searchValue 需要查找的对象的值 如:2
     * @return array 元素的所有索引数组，如返回[1, 2]
     */
    public static function indexesOfByObjectKey(array $array,string $searchKey, $searchValue)
    {
        $indexes = [];
        foreach($array as $index=>$item){
            if(isset($item[$searchKey]) && $item[$searchKey]==$searchValue){
                $indexes[] = $index;
            }
        }
        return $indexes;
    }   

    /**
     * @group 数组修改和添加
     * 从数组中提取一个子数组。
     * 
     * @param array $array 原始数组 如:['a', 'b', 'c', 'd', 'e']
     * @param int $startIndex 开始索引 如:1
     * @param int|null $endIndex 结束索引 如:3
     * @return array 提取的子数组 如:['b', 'c']
     */
    public static function getSubArray(array &$array,int $startIndex,int $endIndex = null)
    {
        return array_slice($array, $startIndex, $endIndex === null ? count($array) - $startIndex : $endIndex - $startIndex);
    }


    /**
     * @group 数组修改和添加
     * 数组的末尾添加一个元素，并返回新的数组。
     * 
     * @param array $array 原始数组 如:['a', 'b', 'c']，执行后返回['a', 'b', 'c', 'd']
     * @param mixed $element 要添加的元素 如:d
     */
    public static function add(array &$array, $element)
    {
        $array[] = $element;
    }

    /**
     * @group 数组修改和添加
     * 合并两个数组，并将结果返回。
     *
     * 该函数将两个数组中的元素合并到一起，返回一个新的数组。
     * 如果数组中的元素是对象，它们将通过引用合并。
     *
     * @param array $array1 第一个要合并的数组。如:['a', 'b', 'c']，执行后返回['a', 'b', 'c', 'd', 'e']
     * @param array $array2 第二个要合并的数组。如:['d', 'e']
     */
    public static function addArray(array &$array1, array $array2)
    {
        $array1 = array_merge($array1, $array2);
    }


    /**
     * @group 数组修改和添加
     * 在数组中的指定位置插入一个或多个元素。
     * 
     * @param array $array 原始数组 如:['a', 'c', 'd'],执行后返回['a', 'b', 'c', 'd']
     * @param mixed $element 要插入的元素 如:b
     * @param int $index 插入位置的索引 如:1
     */
    public static function insert(array &$array, $element, int $index)
    {
        array_splice($array, $index, 0, $element);
    }

    /**
     * @group 数组修改和添加
     * 从数组中移除一个元素，执行后array参数修改
     * 
     * @param array $array 原始数组 如:['a', 'b', 'c']
     * @param mixed $elementToRemove 要移除的元素 如:b
     * @return array 移除元素后的数组 如:['a', 'c']
     */
    public static function removeElement(array &$array, $elementToRemove)
    {
        $array = array_filter($array, function ($element) use ($elementToRemove) {
            return $element !== $elementToRemove;
        });
        $array = array_values($array); // 重新索引数组
    }

    /**
     * @group 数组修改和添加
     * 从数组中移除指定长度的元素段，执行后array参数修改
     *
     * 该函数通过指定的开始索引和长度来移除数组中的元素段。如果未指定长度，则默认移除从开始索引到数组末尾的所有元素。
     *
     * @param array $array 要修改的数组引用。
     * @param int $start 开始移除的索引位置（基于0的索引）。
     * @param int|null $length 要移除的元素数量。如果为null，则默认移除从start索引到数组末尾的所有元素。
     * @throws InvalidArgumentException 如果开始索引不在有效范围内，或者长度为负数。
     */
    public static function remove(array &$array,int $start,int $length = null)
    {
        // 检查开始索引是否在数组的有效范围内
        if ($start < 0 || $start >= count($array)) {
            throw new InvalidArgumentException("Start index is out of bounds.");
        }

        // 如果未指定长度，则默认删除从开始索引到数组末尾的所有元素
        if ($length === null) {
            $length = count($array) - $start;
        }

        // 检查长度是否为正数
        if ($length < 0) {
            throw new InvalidArgumentException("Length must be a non-negative integer.");
        }

        // 计算结束索引
        $end = $start + $length;

        // 使用array_splice来移除指定范围内的元素
        $array = array_splice($array, $start, $length);
    }


    /**
     * @group 数组变换
     * 反转数组，执行后array参数修改
     * 
     * @param array &$array 需要反转的数组 如:['a', 'b', 'c']
     */
    public static function reverse(array &$array)
    {
        $array = array_reverse($array);
    }
 

    /**
     * @group 类型转换
     * 克隆数组。
     * 
     * @param array $array 需要克隆的数组 如:['a', 'b', 'c']
     * @return array 克隆后的数组 如:['a', 'b', 'c']
     */
    public static function clone(array $array)
    {
        return unserialize(serialize($array));
    }

    /**
     * @group 类型转换
     * 返回数组的字符串表示形式。
     * 
     * @param array $array 需要转换的数组 如:['Hello', 'World']
     * @return string 数组的字符串表示 如:Hello, World
     */
    public static function toString(array $array)
    {
        return implode(', ', $array);
    }


    /** 
     * @group 堆栈操作
     * 入栈
     * @param array $array 要操作的数组 如:['a','b']，执行后变更为['a',b','c']
     * @param mixed $value 要添加的元素 如:c
     */
    public static function stackPush(array &$array,$value)
    {
        array_push($array, $value);
    }

    /**
     * @group 堆栈操作
     * 出栈
     * @param array array 要操作的数组 如:['a','b','c']，执行后变更为['a','b']
     * @return mixed 返回被移除的元素 如:c
     */
    public static function stackPop(array &$array)
    {
        return array_pop($array);
    }


    /** 
     * @group 队列操作
     * 入队列
     * @param array $array 要操作的数组 如:['b','c']，执行后变更为['a','b','c']
     * @param mixed $value 要添加的元素 如:a
     */
    public static function queuePush(array &$array,$value)
    {
        array_unshift($array, $value);
    }

    /**
     * @group 队列操作
     * 出队列
     * @param array array 要操作的数组 如:['a','b','c']，执行后变更为['a','b']
     * @return mixed 返回被移除的元素 如:c
     */
    public static function queuePop(array &$array)
    {
        return array_pop($array);
    }
}
